﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using TumbaloSoft.Models;
using System.Security.Cryptography;
using TumbaloSoft.Helpers;
using System.Text;

namespace TumbaloSoft.Controllers
{
    public class AccountController : Controller
    {
        private static Object lockObject = new Object(); 
        private static string secret = "La nota es irrelevante, ahora todo es por la pizza"; //si se cambia este valor ya fue todo XD
        //
        // GET: /Account/LogOn

        public ActionResult LogOn()
        {
            return View();
        }

        private static string RandomString(int size)
        {
            StringBuilder builder = new StringBuilder();
            Random random = new Random();
            char ch;
            for (int i = 0; i < size; i++)
            {
                ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
                builder.Append(ch);
            }
            return builder.ToString();
        }

        //
        // POST: /Account/LogOn

        private static string hashPassword(string password)
        {
            SHA256 hasher = SHA256.Create();
            byte[] passBytes = Encoding.UTF8.GetBytes(password + AccountController.secret );
            byte[] hashBytes = hasher.ComputeHash(passBytes);
            return Convert.ToBase64String(hashBytes);
        }

        public static bool validarLogueo(HttpContextBase contexto)
        {
            HttpCookie myCookie;
            myCookie = contexto.Request.Cookies["username"];
            if (myCookie == null) return false;
            string[] userAndPass = myCookie.Value.Split('|');
            if (userAndPass.Length == 2)
            {
                if (hashPassword(userAndPass[0] + secret) == userAndPass[1]) return true;
            }
            return false;
        }

        public static bool validarPermiso(HttpContextBase contexto)
        {
            HttpCookie myCookie;
            myCookie = contexto.Request.Cookies["idPerfil"];
            if (myCookie == null) return false;
            string[] idAndHash = myCookie.Value.Split('|');
            if (idAndHash.Length != 2 ||hashPassword(idAndHash[0] + secret) != idAndHash[1] )
                return false;
            if (idAndHash[0] == "0") return true;
            List<Vista> listaVistas;
            try
            {
                listaVistas = HelperSesion.selectVistasByIdPerfil(Int32.Parse(idAndHash[0]));
            }
            catch (Exception ex)
            {
                Logger.Current.Error("Se produjo un error al crear la contraseña", ex);
                return false;
            }
            Vista vista = new Vista();
            foreach (Vista v in listaVistas)
            {
                if (v.prUrl.ToUpper() == contexto.Request.Path.ToUpper()
                    || v.prUrl.ToUpper()+"/" == contexto.Request.Path.ToUpper()
                    || (v.prUrl + "/Index").ToUpper() == contexto.Request.Path.ToUpper()) return true;
            }
            return false;
        }

        public static bool crearCuenta(PersonaNatural personaNatural, int idPerfil)
        {
            Usuario user = new Usuario();
            user.prIdPersona = personaNatural.prIdPersona;
            user.prCuenta = personaNatural.prNombre + "." + personaNatural.prApellidoPaterno + "." + personaNatural.prIdPersona;
            user.prCuenta = user.prCuenta.ToLower();
            string defaultPass = AccountController.RandomString(10);
            user.prSalt = AccountController.RandomString(30);
            user.prContrasenha = hashPassword(defaultPass + user.prSalt);
            user.prPerfil = new Perfil();
            user.prPerfil.prIdPerfil = idPerfil;
            try
            {
                lock (lockObject)
                {
                    user.prIdUsuario = HelperSesion.selectMaxCodigo() + 1;
                    HelperSesion.insert(user);
                }
                HomeController cont = new HomeController();
                string mensaje ="Buen día:\n\n Se ha registrado su cuenta satisfactoriamente en el sistema, los datos de su cuenta se encuentran a continuación:"+
                    "\n\n Usuario: "+user.prCuenta+"\n Contraseña: "+defaultPass+"\n\n"+
                    "para cambiar su contraseña, ingrese a la siguiente dirección 200.16.7.115/Account/ChangePassword" +
                    "\n\n Este es un mensaje automático por favor no responder a este correo.";
                cont.SendEmail(personaNatural.prEmail, "Cuenta nueva de Usuario Tumbalo Soft", mensaje);
            }
            catch(Exception ex)
            {
                Logger.Current.Error("Se produjo un error al crear la contraseña",ex);
                return false;
            }
            return true;
        }

        public static int getIdPersona(HttpContextBase contexto)
        {
            HttpCookie myCookie;
            myCookie = contexto.Request.Cookies["idPersona"];
            if (myCookie == null) return 0;
            string[] idAndHash = myCookie.Value.Split('|');
            if (idAndHash.Length == 2)
            {
                if (hashPassword(idAndHash[0] + secret) == idAndHash[1])
                {
                    int result;
                    if (Int32.TryParse(idAndHash[0], out result)) return result;
                    return 0;
                } 
            }
            return 0;
        }

        public static Usuario getUsuario(HttpContextBase contexto)
        {
            HttpCookie myCookie;
            myCookie = contexto.Request.Cookies["username"];
            if (myCookie == null) return null;
            string[] userAndPass = myCookie.Value.Split('|');
            if (userAndPass.Length == 2)
            {
                if (hashPassword(userAndPass[0] + secret) == userAndPass[1])
                {
                    Usuario user;
                    try
                    {
                        user = HelperSesion.selectUsuarioByCuenta(userAndPass[0]);
                    }
                    catch (Exception ex)
                    {
                        Logger.Current.Error("Se produjo un error al obtener el usuario", ex);
                        return null;
                    }
                    if(user != null) return user;
                }
            }
            return null;
        }

        public static int getIdPerfil(HttpContextBase contexto)
        {
            HttpCookie myCookie;
            myCookie = contexto.Request.Cookies["idPerfil"];
            if (myCookie == null) return 0;
            string[] idAndHash = myCookie.Value.Split('|');
            if (idAndHash.Length == 2)
            {
                if (hashPassword(idAndHash[0] + secret) == idAndHash[1])
                {
                    int result;
                    if (Int32.TryParse(idAndHash[0], out result)) return result;
                    return 0;
                }
            }
            return 0;
        }

        public bool validateLogin(HttpContextBase contexto)
        {
            HttpCookie myCookie;
            myCookie = contexto.Request.Cookies["username"];
            if (myCookie == null) return false;
            string [] userAndPass = myCookie.Value.Split('|');
            if (userAndPass.Length == 2)
            {
                if (hashPassword(userAndPass[0] + secret) == userAndPass[1]) return true;
            }
            return false;
        }

        [HttpPost]
        public ActionResult LogOn(Usuario model, string returnUrl , string recuerdame)
        {
            //hash password  
            if (model.prContrasenha==null)
            {
                model.prContrasenha = "";
            }
            Usuario user;
            try
            {
                user = HelperSesion.loginCorrecto(model);
            }
            catch(Exception ex)
            {
                Logger.Current.Error("Se produjo un error al validar el login", ex);
                return View("~/Views/Shared/Error.cshtml");
            }
            if (user == null)
            {
                ModelState.AddModelError("prCuenta", "El Usuario o Contraseña son Incorrectos");
                return View(model);
            }
            string hPass = hashPassword(model.prContrasenha + user.prSalt);
            model.prContrasenha = hPass;
            if (model.prContrasenha == user.prContrasenha)
            {
                HttpCookie myCookie = new HttpCookie("username", model.prCuenta + "|" + hashPassword(model.prCuenta+secret));
                HttpCookie idCookie = new HttpCookie("idPersona", user.prIdPersona + "|" + hashPassword(user.prIdPersona + secret));
                HttpCookie idPerfil = new HttpCookie("idPerfil", user.prPerfil.prIdPerfil + "|" + hashPassword(user.prPerfil.prIdPerfil + secret));
                if (recuerdame == "true")
                {
                    myCookie.Expires = DateTime.Now.AddYears(1);//la cookie tendra validez de 1 año
                    idCookie.Expires = DateTime.Now.AddYears(1);
                    idPerfil.Expires = DateTime.Now.AddYears(1);
                }
                else
                {
                    myCookie.Expires = DateTime.MinValue;
                    idCookie.Expires = DateTime.MinValue;
                    idPerfil.Expires = DateTime.MinValue;
                }
                HttpContext.Response.Cookies.Add(myCookie);
                HttpContext.Response.Cookies.Add(idCookie);
                HttpContext.Response.Cookies.Add(idPerfil);
			 if (returnUrl == null && user.prPerfil.prIdPerfil == 0) returnUrl = "/PerfilSuperAdmin";
                if (returnUrl == null && user.prPerfil.prIdPerfil == 1) returnUrl = "/PerfilPropietario";
                 if (returnUrl == null && user.prPerfil.prIdPerfil == 2) returnUrl = "/PerfilAdministrador";
                if (returnUrl== null && user.prPerfil.prIdPerfil == 3) returnUrl = "/PerfilAdministradorGeneral";
                if (returnUrl == null && user.prPerfil.prIdPerfil == 4) returnUrl = "/Ventas";
                if (returnUrl == null && user.prPerfil.prIdPerfil == 5) returnUrl = "/PerfilVendedor";
                ViewBag.mensaje = "Se inició sesión con éxito";
                ViewBag.returnURL = returnUrl;
                return View("~/Views/Shared/Exito.cshtml"); 
            }
            ModelState.AddModelError("prCuenta","El Usuario o Contraseña son Incorrectos");
            return View(model);
        }

        //
        // GET: /Account/LogOff

        public ActionResult LogOff()
        {

            HttpCookie blankCookieUser = new HttpCookie("username", "");// se setea la cookie a vacia asi ya se considera que no existe
            HttpContext.Response.Cookies.Add(blankCookieUser);
            HttpCookie blankCookiePerfil = new HttpCookie("idPerfil", "");
            HttpContext.Response.Cookies.Add(blankCookiePerfil);
            HttpCookie blankCookiePersona = new HttpCookie("idPersona", "");
            HttpContext.Response.Cookies.Add(blankCookiePersona);
            return RedirectToAction("Index", "Home");
        }

        //
        // GET: /Account/Register

        public ActionResult Register()
        {
            return View();
        }

        //
        // POST: /Account/Register

        [HttpPost]
        public ActionResult Register(Usuario usuario, string confirmacion)
        {
            if (confirmacion != usuario.prContrasenha) ModelState.AddModelError("prContrasenha", "Amabs contraseñas deben coincidir");
            bool existe;
            try
            {
                existe = HelperSesion.yaExiste(usuario);
            }
            catch(Exception ex)
            {
                Logger.Current.Error("Se produjo un error al registrar un usuario", ex);
                return View("~/Views/Shared/Error.cshtml");
            }
            if (existe)
            {
                ModelState.AddModelError("prCuenta", "Ya existe ese usuario");
            }
            if (ModelState.IsValid)
            {
                try
                {
                    string salt = AccountController.RandomString(30);
                    usuario.prSalt = salt;
                    usuario.prContrasenha = hashPassword(usuario.prContrasenha + salt);
                    lock (lockObject)
                    {
                        usuario.prIdUsuario = HelperSesion.selectMaxCodigo() + 1;
                        HelperSesion.insert(usuario);
                    }
                }
                catch(Exception ex)
                {
                    Logger.Current.Error("Se produjo un error al crear un usuario", ex);
                    return View("~/Views/Shared/Error.cshtml");
                }
                return RedirectToAction("Index", "Home");
            }
            return View(usuario);

        }

        //
        // GET: /Account/ChangePassword

        public ActionResult ChangePassword()
        {
            if (!AccountController.validarLogueo(HttpContext))
            {
                return RedirectToAction("LogOn", "Account", new { returnUrl = HttpContext.Request.Path });
            }
            return View();
        }

        //
        // POST: /Account/ChangePassword

        [HttpPost]
        public ActionResult ChangePassword(ChangePasswordModel model)
        {
            if (!AccountController.validarLogueo(HttpContext))
            {
                return RedirectToAction("LogOn", "Account", new { returnUrl = HttpContext.Request.Path });
            }

            if (ModelState.IsValid)
            {
                Usuario user;
                try
                {
                    user = AccountController.getUsuario(HttpContext);
                }
                catch (Exception ex)
                {
                    Logger.Current.Error("Error al obtener el usuario actual", ex);
                    return View("~/Views/Shared/Error.cshtml");
                }
                user.prContrasenha = hashPassword(model.NewPassword + user.prSalt);
                try
                {
                    HelperSesion.cambiarPassword(user);
                }
                catch(Exception ex)
                {
                    Logger.Current.Error("Error al cambiar", ex);
                    return View("~/Views/Shared/Error.cshtml");
                }

                return RedirectToAction("LogOn", "Account");
            }

            // Si llegamos a este punto, es que se ha producido un error y volvemos a mostrar el formulario
            return View(model);
        }

        //
        // GET: /Account/ChangePasswordSuccess

        public ActionResult ChangePasswordSuccess()
        {
            return View();
        }

        #region Status Codes
        private static string ErrorCodeToString(MembershipCreateStatus createStatus)
        {
            // Vaya a http://go.microsoft.com/fwlink/?LinkID=177550 para
            // obtener una lista completa de códigos de estado.
            switch (createStatus)
            {
                case MembershipCreateStatus.DuplicateUserName:
                    return "El nombre de usuario ya existe. Escriba un nombre de usuario diferente.";

                case MembershipCreateStatus.DuplicateEmail:
                    return "Ya existe un nombre de usuario para esa dirección de correo electrónico. Escriba una dirección de correo electrónico diferente.";

                case MembershipCreateStatus.InvalidPassword:
                    return "La contraseña especificada no es válida. Escriba un valor de contraseña válido.";

                case MembershipCreateStatus.InvalidEmail:
                    return "La dirección de correo electrónico especificada no es válida. Compruebe el valor e inténtelo de nuevo.";

                case MembershipCreateStatus.InvalidAnswer:
                    return "La respuesta de recuperación de la contraseña especificada no es válida. Compruebe el valor e inténtelo de nuevo.";

                case MembershipCreateStatus.InvalidQuestion:
                    return "La pregunta de recuperación de la contraseña especificada no es válida. Compruebe el valor e inténtelo de nuevo.";

                case MembershipCreateStatus.InvalidUserName:
                    return "El nombre de usuario especificado no es válido. Compruebe el valor e inténtelo de nuevo.";

                case MembershipCreateStatus.ProviderError:
                    return "El proveedor de autenticación devolvió un error. Compruebe los datos especificados e inténtelo de nuevo. Si el problema continúa, póngase en contacto con el administrador del sistema.";

                case MembershipCreateStatus.UserRejected:
                    return "La solicitud de creación de usuario se ha cancelado. Compruebe los datos especificados e inténtelo de nuevo. Si el problema continúa, póngase en contacto con el administrador del sistema.";

                default:
                    return "Error desconocido. Compruebe los datos especificados e inténtelo de nuevo. Si el problema continúa, póngase en contacto con el administrador del sistema.";
            }
        }
        #endregion
    }
}
